//根据类型值（挑选｜忽略）对象类型的属性
interface Person {
  name: string;
  age: number;
  address: string;
}
//1---------------------------------------
//判断两个类型是否完全一致（类型层级、结构）
type IsEuqal<T, K, Success, Fail = never> = [T] extends [K]
  ? [K] extends [T] //从类型的角度出发，两个类型完全一致，互相extends，才可以
    ? Success
    : Fail
  : Fail;
//或得指定类型的key的联合类型,
type ExtractKey<T extends object, U> = {
  [K in keyof T]: IsEuqal<T[K], U, K>;
}[keyof T];

type P0 = ExtractKey<Person, string>; //或得指定类型的key的联合类型
type PickKeysBuyValue = Pick<Person, ExtractKey<Person, string>>; //挑选出指定类型的类型
type OmitKeysBuyValue = Omit<Person, ExtractKey<Person, string>>; //忽略出指定类型的类型
//2，通过公共方法来（挑选｜忽略）---------------------------------------
//判断两个类型是否完全一致（类型层级、结构）
type IsEuqal2<T, K, Success, Fail = never> = [T] extends [K]
  ? [K] extends [T] //从类型的角度出发，两个类型完全一致，互相extends，才可以
    ? Success
    : Fail
  : Fail;
//或得指定类型的key的联合类型，通过公共方法来判断
type ExtractKey2<T extends object, U, O = false> = {
  [K in keyof T]: IsEuqal<
    T[K],
    U,
    IsEuqal<O, true, never, K>,
    IsEuqal<O, true, K, never>
  >;
}[keyof T];

type P01 = ExtractKey2<Person, string>; //或得指定类型的key的联合类型
type P02 = ExtractKey2<Person, string,true>; //或得忽略指定类型的key的联合类型
type PickKeysBuyValue1 = Pick<Person, ExtractKey2<Person, string>>; //挑选出指定类型的类型
type OmitKeysBuyValue1 = Pick<Person, ExtractKey2<Person, string, true>>; //忽略出指定类型的类型

//2，使用模版字符串来（挑选｜忽略）---------------------------------------
//里面有一个很重要的功能：重映射
type PickKeysBuyValue2<T extends object,U>={
    //直接将对象的属性给忽略了
    //循环对象的key，看值的类型是否相同，如果相同留下这个key，以下2种写法都可以
    // [K in keyof T as T[K] extends U ? K : never]:T[K]
    [K in keyof T as IsEuqal2<T[K],U,K,never>]:T[K]
}
type p3=PickKeysBuyValue2<Person,string>
